package com.nwpu.coursesupport.service.imple;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.nwpu.coursesupport.criteria.ClassSearchCriteria;
import com.nwpu.coursesupport.criteria.ClassViewSearchCriteria;
import com.nwpu.coursesupport.entity.Assistant;
import com.nwpu.coursesupport.entity.Class;
import com.nwpu.coursesupport.entity.Class.ClassDate;
import com.nwpu.coursesupport.entity.Class.DateItem;
import com.nwpu.coursesupport.entity.Course;
import com.nwpu.coursesupport.entity.Lesson;
import com.nwpu.coursesupport.entity.bean.JSONResult;
import com.nwpu.coursesupport.enumeration.ClassType;
import com.nwpu.coursesupport.enumeration.LessonCreateType;
import com.nwpu.coursesupport.enumeration.LessonStatus;
import com.nwpu.coursesupport.enumeration.LessonType;
import com.nwpu.coursesupport.exception.ClassDealException;
import com.nwpu.coursesupport.exception.LessonBatchAddException;
import com.nwpu.coursesupport.exception.TransactionException;
import com.nwpu.coursesupport.mapper.AssistantMapper;
import com.nwpu.coursesupport.mapper.ClassMapper;
import com.nwpu.coursesupport.mapper.CourseMapper;
import com.nwpu.coursesupport.mapper.LessonMapper;
import com.nwpu.coursesupport.service.AbstractService;
import com.nwpu.coursesupport.service.ClassService;
import com.nwpu.coursesupport.service.param.ClassServiceParam;
import com.nwpu.coursesupport.tool.DateUtil;
import com.nwpu.coursesupport.tool.RandomUtil;
import com.nwpu.coursesupport.tool.ServiceUtil;
import com.nwpu.coursesupport.tool.StringUtil;
import com.nwpu.coursesupport.tool.UpdateUtil;
import com.nwpu.coursesupport.view.CCView;
import com.nwpu.coursesupport.view.ClassView;

@Service("classService")
public class ClassServiceImple extends AbstractService implements ClassService{
    @Autowired
    private ClassMapper classMapper;
    @Autowired
    private AssistantMapper assistantMapper;
    @Autowired
    private CourseMapper courseMapper;
    @Autowired
    private LessonMapper lessonMapper;
    
    private final static int WEEKDAY=7;
    
    protected static Logger logger = LoggerFactory.getLogger(ClassServiceImple.class);
   
    public JSONResult courseView(int id){
    	JSONResult rst = new JSONResult();
        rst.fail();
        if(id<=0){
        	logger.error("参数有误");
        	return rst.fail("参数有误");
        }
        Course course=this.courseMapper.findById(id);
        if(course==null){
        	logger.error("该课程不存在");
        	rst.fail("该课程不存在");
        }
        
        ClassSearchCriteria sc =new ClassSearchCriteria();
        sc.setClassType(ClassType.CLASS);
        sc.setCourseId(id);
        List<Class> classes=this.classMapper.find(sc);
        //List<ClassNode> classes=this.getChilden(sc);
        CCView view=new CCView();
        UpdateUtil.setValues(view, course);
        view.setClasses(classes);
        rst.success();
        rst.addData("course", view);
        rst.addData("courseId",id);
        return rst;
    }

	@Override
	public Integer getClassIDByClassName(String className) {
		return classMapper.getClassIDByClassName(className);
	}

	@Override
	public List<Class> getClassByCourseID(Integer courseID) {
		return classMapper.getClassByCourseID(courseID);
	}

	public JSONResult findClassView(ClassViewSearchCriteria sc){
    	JSONResult rst = new JSONResult();
        rst.fail();
        if(sc==null || StringUtil.isEmpty(sc.getClassCode())){
        	logger.error("参数有误");
        	return rst.fail("参数有误");
        }
        sc.setClassId(null);
        ClassView view=this.classMapper.getClassView(sc);
        if(view==null){
        	logger.error("该课程不存在");
        	return rst.fail("该课程不存在");
        }
        rst.addData("classView", view);
        rst.success();
        return rst;
    }
    
    public JSONResult detail(int id){
        JSONResult rst = new JSONResult();
        rst.fail();
        if(id<=0){
        	logger.error("参数有误");
        	return rst.fail("参数有误");
        }
        
        Class c = this.classMapper.findById(id);
        c.setTheoryDate(ServiceUtil.parseDate(c.getTheoryDateBytes()));
        c.setLabDate(ServiceUtil.parseDate(c.getLabDateBytes()));//格式化时间
        rst.addData("class", c);
        rst.success();
        return rst;
    }
    
   
    public JSONResult list(ClassSearchCriteria sc){
        JSONResult rst = new JSONResult();
        rst.fail();
       
        if (sc == null ){
        	logger.error("参数有误");
        	return rst.fail("参数有误");
        }
        if(sc.getCourseId()!=null&&sc.getClassType()==null){
        	sc.setClassType(ClassType.CLASS);
        }
        
        List<Class> list = this.classMapper.find(sc);
        if (list == null){
        	logger.error("参数有误");
            return rst.fail("参数有误");
        }
        rst.addData("list", list);
        rst.success();
        return rst;
    }

    /**
     * 递归寻找
     * @param sc
     * @return
     */
    private List<ClassNode> getChilden(ClassSearchCriteria sc){
    	List<Class> list=this.classMapper.find(sc);
    	List<ClassNode> result=new ArrayList<ClassNode>();
    	if(list==null||list.size()<=0){
    		return result;
    	}
    	ClassNode node=null;
    	for(Class c : list){
    		node=new ClassNode();
    		UpdateUtil.setValues(node, c);
    		sc=new ClassSearchCriteria();
    		sc.setFid(c.getId());
    		sc.setCourseId(c.getCourseId());
    		node.setNodes(getChilden(sc));
    		result.add(node);
    	}
    	return result;
    }
    	
    public JSONResult recurList(ClassSearchCriteria sc){
        JSONResult rst = new JSONResult();
        rst.fail();
      
        if (sc == null){
        	logger.error("参数有误");
        	return rst.fail("参数有误");
        }
        if(sc.getCourseId()!=null){
        	sc.setClassType(ClassType.CLASS);
        }
        List<ClassNode> list = this.getChilden(sc);
        if (list == null ){
        	logger.error("参数有误");
            return rst.fail("参数有误");
        }
        
        rst.addData("list", list);
        rst.success();
        return rst;
    }
    
    @Transactional(propagation = Propagation.REQUIRED)
    public JSONResult create(ClassServiceParam.CreateParam p) throws TransactionException{
        JSONResult rst = new JSONResult();
        rst.fail();
       
       if (p == null){
    	   logger.error("参数p为空");
            return rst.fail("参数有误");
        }
        if(p.getClassType()==null){
        	logger.error("班级类型为空");
        	return rst.fail("班级类型为空");
        }
        Class c=p;
       
    	Course course=this.courseMapper.findById(c.getCourseId());
    	if(course==null){
    		logger.error("查询课程不存在");
    		return rst.fail("该课程不存在");
    	}
    	int createId=(int) getSession().getAttribute("id");
    	c.setCreateId(createId);
    	c.setCreateDate(new Date());
    	
        switch(p.getClassType()){
        case CLASS:
        	rst=dealCLASS(c);
        	break;
        case MANAGETEAM:
        	rst=dealMANAGETEAM(c);
        	break;
        case TASKTEAM:
        	rst=dealTASKTEAM(c);
        	break;
        default:
        	logger.error("参数有误");
        	rst.fail("参数有误");	
        }
        if(!rst.isSuccess()){
        	logger.error("保存班级失败，并抛出异常ClassDealException");
        	throw new ClassDealException("保存班级失败");
        };
        rst.success();
        return rst;
    }

    private JSONResult dealCLASS(Class c) throws LessonBatchAddException{
    	
    	JSONResult rst=new JSONResult();
    	rst.fail();
    	
    	if(c.getHasTheory()==1){//存在理论课
    		String dateBytes=ServiceUtil.serializeDate(c.getTheoryDate());
    		if(dateBytes==null){
    			logger.error("理论课时间错误");
    			return rst.fail("理论课时间错误");
    		}
    		c.setTheoryDateBytes(dateBytes);
    	}
    	if(c.getHasLab()==1){//存在实验课
    		String dateBytes=ServiceUtil.serializeDate(c.getLabDate());
    		if(dateBytes==null){
    			logger.error("实验课时间错误");
    			return rst.fail("实验课时间错误");
    		}
    		c.setLabDateBytes(dateBytes);
    	}
    	c.setFid(0);
    	if(!this.classMapper.save(c)){
    		logger.error("保存班级失败");
    		throw new ClassDealException("保存班级失败");
    	}
    	
    	if(c.getHasTheory()==1){
    		if(!addLesson(c.getTheoryDate(),LessonType.THEORY,c)){
    			logger.error("添加理论课堂出现错误");
    			throw new LessonBatchAddException("添加理论课堂出现错误");
    		}
    	}
    	if(c.getHasLab()==1){
    		if(!addLesson(c.getLabDate(),LessonType.LAB,c)){
    			logger.error("添加实验课堂出现错误");
    			throw new LessonBatchAddException("添加实验课堂出现错误");
    		}
    	}
    	rst.success();
    	return rst;
    }
    
    private boolean addLesson(ClassDate date,LessonType type,Class c){
    	if(date==null||date.getDate()==null||date.getDate().size()<=0){//date 需要判断 校验  目前出现了 空指针异常
    		return false;
    	}
    	List<DateItem> list=date.getDate();
    	if(list==null||list.size()<0){
    		logger.error("上课时间为空，创建失败");
    		return false;
    	}
    	int sumOrWeeks=date.getSumWeeks();
    	List<Lesson> lessons=new ArrayList<Lesson>();
    	Lesson lesson=null;
    	int time=1;
    	for(int i=0;i<sumOrWeeks;i++){
    		for(DateItem item : list){
    			lesson=new Lesson();
    			lesson.setClassId(c.getId());
    			lesson.setClassName(c.getName());
    			lesson.setType(type);
    			lesson.setBeginDate(DateUtil.getNextDate(item.getBegin(),i*WEEKDAY));
    			lesson.setEndDate(DateUtil.getNextDate(item.getEnd(),i*WEEKDAY));
    			lesson.setTimeClass(time++);
    			lesson.setDurationCourse(DateUtil.getDuration(lesson.getBeginDate(),lesson.getEndDate()));
    			lesson.setCreateType(LessonCreateType.NORMAL);
    			lesson.setLocation(item.getLocation());
    			lessons.add(lesson);
    		}
    	}
    	if(lessons.size()<=0){
    		logger.error("该班级无课堂，创建课堂失败"+type.name());
    		return false;
    	}
    	if(this.lessonMapper.batchSave(lessons)!=lessons.size()){
    		logger.error("创建课堂失败");
    		return false;
    	}
    	return true;
    }
    
    

    private JSONResult dealMANAGETEAM(Class c){
    	JSONResult rst=new JSONResult();
    	rst.fail();
    	if(c.getFid()==0){
    		logger.error("c.getFid()==0，操作有误");
    		return rst.fail("操作有误");
    	}
    	Class ca=this.classMapper.findById(c.getFid());
    	if(ca==null||ca.getFid()!=0){
    		logger.error("该班级父班级不存在");
    		return rst.fail("该班级父班级不存在");
    	}
    	Assistant assistant=this.assistantMapper.findById(c.getManagerId());
    	if(assistant==null){
    		logger.error("该助教不存在");
    		return rst.fail("该助教不存在");
    	}
    	c.setManagerName(assistant.getName());
    	
    	if(!this.classMapper.save(c)){
    		logger.error("管理班级保存失败");
    		return rst.fail("添加失败");
    	}
    	rst.success();
    	rst.addData("class", c);
    	return rst;
    }
    
    private JSONResult dealTASKTEAM(Class c){
    	JSONResult rst=new JSONResult();
    	rst.fail();
    	if(c.getFid()==0){
    		logger.error("参数有误");
    		return rst.fail("参数有误");
    	}
    	Class ca=this.classMapper.findById(c.getFid());
    	if(ca==null||ca.getFid()!=0){
    		logger.error("该班级副班级不存在");
    		return rst.fail("该班级副班级不存在");
    	}
    	
    	if(!this.classMapper.save(c)){
    		logger.error("个人班级保存失败");
    		return rst.fail("保存失败");
    	}
  
    	rst.success();
    	rst.addData("class", c);
    	return rst;
    }
    
    
    public JSONResult update(ClassServiceParam.UpdateParam p){
        JSONResult rst = new JSONResult();
        rst.fail();
        
        if (p == null || p.getId() <= 0){
        	logger.error("参数有误");
            return rst.fail("参数有误");
        }
        
        Class c = this.classMapper.findById(p.getId());
        if (c == null){
        	logger.error("该班级不存在");
            return rst.fail("该班级不存在");
        }
        
        if (UpdateUtil.setValues(c, p) > 0){
            if (!this.classMapper.update(c)){
            	logger.error("修改失败");
                return rst.fail("修改失败");
            }
        }
        
        rst.addData("class", c);
        rst.success();
        return rst;
    }
   public static class ClassNode extends Class{
    	private List<ClassNode> nodes;

    	public List<ClassNode> getNodes() {
    		return nodes;
    	}

    	public void setNodes(List<ClassNode> nodes) {
    		this.nodes = nodes;
    	}
    	
    }

}
